/*
 *   histroy: created at July 1, 2010
 */

#ifndef __GIGIONE_H__
#define __GIGIONE_H__

#ifdef __cplusplus
extern "C" {
#endif

#if !defined(WINDOWS) && ( defined(_WIN32) || defined(_WIN64) )
  #define WINDOWS  1
#endif

/* Marco defined and typedef
 *            Basic macro and type
 *
 *   GIGI_TRUE , GIGI_FALSE     : bool constant  
 *   GIGI_COUNT_OF              : count of the array
 *   GIGI_LPCSTR, GIGI_LPSTR    : string type
 *   GIGI_UINT64                : 
 *
 */
#define GIGI_TRUE         1
#define GIGI_FALSE        0
#define GIGI_COUNT_OF(s)  (sizeof (s)/sizeof (*(s)))

typedef const char*       GIGI_LPCSTR;
typedef char*             GIGI_LPSTR;

#ifdef WINDOWS
  typedef unsigned __int64   GIGI_UINT64;
#else
  typedef unsigned long long GIGI_UINT64;
#endif


/*
 * Marcro defined 
 *       GIGI_ID and user macro for GIGI_ID
 *
 * GIGI_ID_IP
 * GIGI_ID_PORT
 * GIGI_ID_FLAG
 * GIGI_ID_MAKE1 
 * GIGI_ID_MAKE
 */

#define GIGI_ID           GIGI_UINT64
#define GIGI_ID_IP(n)    ((unsigned)( (n) >> 32 ) )
#define GIGI_ID_PORT(n)  ((unsigned short)( (n) >> 16 ) & 0xFFFF )
#define GIGI_ID_FLAG(n)  ((unsigned short)( (n) & 0xFFFF ) )
#define GIGI_ID_MAKE1(n) (n)
#define GIGI_ID_MAKE(ip,port,flag) \
  ((((GIGI_UINT64)(ip)) << 32) | \
  (((GIGI_UINT64)(port)) << 16) | \
  ((GIGI_UINT64)(flag)) )


/* Error Code */
#define GIGI_OK                       0
#define GIGI_E_INVALID_CONN_STRING   -1
#define GIGI_E_BIND_FAILED           -2
#define GIGI_E_NO_IP                 -3
#define GIGI_E_THREAD_ERROR          -4
#define GIGI_E_INVALID_HANDLE        -5
#define GIGI_E_MEM_ERROR             -6
#define GIGI_E_PACKET_ERROR          -10
#define GIGI_E_INVALID_ID            -11
#define GIGI_E_READ_ERROR            -15
#define GIGI_E_WRITE_ERROR           -16
#define GIGI_E_SOCKET_ERROR          -17
#define GIGI_E_TIMEOUT               -18
#define GIGI_E_CLOSED_BY_PEER        -19
#define GIGI_E_NO_SERVICE            -20
#define GIGI_E_OUT_OF_MEMORY         -21
#define GIGI_E_SERVER_BUSY           -22
#define GIGI_E_CONNECT_ERROR         -23

/* predefined service id */
#define GIGI_SERVICE_GIGI            GIGI_ID_MAKE1(1)
#define GIGI_SERVICE_NETLOG          GIGI_ID_MAKE1(2)
#define GIGI_SERVICE_CMD_GETID       1


/*
 * Basic handle definition of GIGIONE object
 *
 * GIGIONE      : GIGI module context
 * GIGI_SOCKET  : GIGI socket handle
 * GIGI_SERVICE : service handle
 * GIGI_MPI     : a group communication environement
 */
struct gigi_context_t;
struct gigi_socket_context_t;
struct gigi_service_context_t;
struct gigi_mpi_context_t;
struct gigi_stream_vt;
struct gmpi_func_def_t;
struct gigi_type_def_t;
struct gigi_type_list_t;

typedef struct gigi_context_t           * GIGIONE;
typedef struct gigi_socket_context_t    * GIGI_SOCKET;
typedef struct gigi_service_context_t   * GIGI_SERVICE;
typedef struct gigi_mpi_context_t       * GIGI_MPI;
typedef struct gigi_stream_vt          ** GIGI_STREAM;
typedef struct gmpi_func_def_t          * GMPI_FUNC_DEF;
typedef struct gigi_type_def_t          * GIGI_TYPE_DEF;
typedef struct gigi_type_list_t         * GIGI_TYPE_LIST;

/*
 * type id in GIGIONE
 */
#define GIGI_TYPE_CHAR          1
#define GIGI_TYPE_INT16         2
#define GIGI_TYPE_INT32         3
#define GIGI_TYPE_INT64         4
#define GIGI_TYPE_DOUBLE        5

#define GIGI_TYPE_OBJECT_BEGIN  6
#define GIGI_TYPE_VARIANT       6
#define GIGI_TYPE_STRING        7
#define GIGI_TYPE_ARGV          8
#define GIGI_TYPE_STREAM        9

#define GIGI_TYPE_ARRAY         0x8000
#define GIGI_TYPE_PTR           0x4000
#define GIGI_TYPE_ARRAY_PTR     (0x4000 | 0x8000)
#define GIGI_TYPE_MASK          0x3FFF

#define GIGI_TYPE_ID            GIGI_TYPE_INT64
#define GIGI_TYPE_DATETIME      GIGI_TYPE_INT64
#define GIGI_TYPE_BUFFER        (GIGI_TYPE_CHAR | GIGI_TYPE_ARRAY)
#define GIGI_TYPE_PTR_BUF       (GIGI_TYPE_CHAR | GIGI_TYPE_ARRAY_PTR)
#define GIGI_TYPE_PTR_STRING    (GIGI_TYPE_STRING | GIGI_TYPE_PTR)

/*
 * reduce operation definition
 */
#define GIGI_SUM                ((GIGI_REDUCE_OP)1)
#define GIGI_MAX                ((GIGI_REDUCE_OP)2)
#define GIGI_MIN                ((GIGI_REDUCE_OP)3)
#define GIGI_AND                ((GIGI_REDUCE_OP)4)
#define GIGI_OR                 ((GIGI_REDUCE_OP)5)
#define GIGI_XOR                ((GIGI_REDUCE_OP)6)
#define GIGI_REDUCE_EOF         ((GIGI_REDUCE_OP)7)

/*
 * callback for GIGIONE
 */
typedef enum GIGI_CALLBACK_MSG
{
  GIGI_CB_CLEAN_TIMEOUT_CONN    = 1,
  GIGI_CB_IN_IDLE               ,
  GIGI_CB_TEST                  ,
}GIGI_CALLBACK_MSG;

/*
 * function type for GIGIONE
 */
typedef void (*GIGI_MPI_FUNC)     (GIGI_MPI mpi, void * param);
typedef void (*GIGI_MPI_BROKER)   (GIGIONE gg, GIGI_SOCKET fd, void * param);
typedef int  (*GIGI_SERVICE_FUNC) (void * ctx, GIGI_SOCKET fd);
typedef void (*GIGI_CALLBACK)     (void * ctx, int msg, int p1, int p2);
typedef void (*GIGI_REDUCE_OP)    (void * a, void * b);

/*
 * GIGI_STREAM
 */
struct gigi_stream_vt
{
  int (*_read) (GIGI_STREAM, void *, int);
  int (*_write)(GIGI_STREAM, const void *, int);
  int (*_close)(GIGI_STREAM, int);
  int (*_cntl) (GIGI_STREAM, int,...);
};

#define gigi_fclose(s) do { if (s) (*s)->_close(s, 0); (s) = NULL; } while(0)
#define gigi_fwrite(s,buf,sz) ((*s)->_write (s, buf, sz))
#define gigi_fread(s,buf,sz)  ((*s)->_read  (s, buf, sz))
#define gigi_fcntl(s,id,...)  ((*s)->_cntl  (s, id, __VA_ARGS__))

/*
 * struct gmpi_func_def_t
 *
 */
struct gmpi_func_def_t
{
  const char*      _name;
  GIGI_MPI_FUNC    _func;
  GIGI_MPI_BROKER  _broker;
};

#define GMPI_FUNC_MAP_BEGIN(mpi_func_map)   \
  struct gmpi_func_def_t mpi_func_map[] = {

#define GMPI_FUNC_MAP(nm)                   \
  {#nm, nm, NULL},

#define GMPI_FUNC_MAP_BROKER(nm)            \
  {#nm, nm, broker_##nm},

#define GMPI_FUNC_MAP_RPC(nm)               \
  {#nm, NULL, nm},

#define GMPI_FUNC_MAP_END(mpi_func_map)     \
  {(void *)0, (void *)0, (void *)0}};


/* struct gigi_type_def_t & gigi_type_list
 *        custom object send/recv for GIGIONE
 *
 */
struct gigi_type_def_t
{
  int   _type;
  int (*_send) (GIGI_STREAM, int, const void *, int);
  int (*_recv) (GIGI_STREAM, int, void *, int *);
};

struct gigi_type_list_t
{
  struct gigi_type_list_t * _next;
  struct gigi_type_list_t * _prev;
  GIGI_TYPE_DEF             _types;  /* this is type def array */
                                     /*  end of {0,NULL,NULL}  */
};


/*   APIs list -- part 1
 *
 *   gigi_create
 *   gigi_free
 *   gigi_errno
 *   gigi_my_id
 *   gigi_gen_id
 *   gigi_set_callback
 *   gigi_kill_callback
 */

/*
 * function gigi_create
 *          init and create a GIGIONE context
 * return           --- the handle of GIGIONE context
 * conn_string(in)  --- initialize string for GIGIONE
 * token_string(in) --- token string for GIGIONE
 * errcode(out)     --- error code return
 */
GIGIONE gigi_create (GIGI_LPCSTR conn_string, GIGI_LPCSTR token_string,
                     int port, int * errcode);

/*
 * function gigi_free
 *          free the GIGIONE context
 * return --- GIGI_OK if success, else return error code
 * gg     --- the handle of GIGIONE context
 */
int gigi_free (GIGIONE gg);

/*
 * function gigi_errno
 *          return error code of GIGIONE context
 * return --- GIGI_OK if success, else return error code
 * gg     --- the handle of GIGIONE context
 */
int gigi_errno (GIGIONE gg);

/*
 * function gigi_my_id
 *          return my id of GIGIONE context
 * return --- my id
 * gg     --- the handle of GIGIONE context
 */
GIGI_ID gigi_my_id (GIGIONE gg);

/*
 * function  gigi_gen_id
 *           generate a unique id
 * return --- a uniform GIGI ID
 * gg     --- the handle of GIGIONE context
 */
GIGI_ID gigi_gen_id (GIGIONE gg);

/*
 * function 
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
void * gigi_set_callback (GIGIONE gg, GIGI_CALLBACK func, void * ctx);

/*
 * function 
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
int gigi_kill_callback (void * callback);


/*  APIs list -- part 2
 *
 *  gigi_aton
 *  gigi_aton_list
 *  gigi_ntoa
 */

/*
 * function 
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
GIGI_ID gigi_aton (GIGIONE gg, GIGI_LPCSTR addr, int def_port);

/*
 * function 
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
int gigi_aton_list (GIGIONE gg, GIGI_LPCSTR addrs, int def_port,
                    GIGI_ID * id, int count);

/*
 * function 
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
char * gigi_ntoa (GIGI_ID node, char * addr);


/* APIs list -- part 3
 *
 * gigi_socket
 * gigi_closesocket
 * gigi_get_peer_id
 * gigi_send
 * gigi_recv
 * gigi_accept
 * gigi_open_service
 * gigi_close_service
 * gigi_send_object
 * gigi_recv_object
 * gigi_type_register
 * gigi_type_def
 */

/*
 * function gigi_socket
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
GIGI_SOCKET gigi_socket (GIGIONE gg, GIGI_ID node, GIGI_ID service_id,
                         int raw_mode, int * errcode);

/*
 * function gigi_closesocket
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
int gigi_closesocket (GIGI_SOCKET fd, int forceclose);

/*
 * function 
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
GIGI_ID gigi_get_peer_id (GIGI_SOCKET fd);

/*
 * function gigi_send
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
int gigi_send (GIGI_SOCKET fd, const void * buff, int size);

/*
 * function gigi_recv
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
int gigi_recv (GIGI_SOCKET fd, void * buf, int size);

/*
 * function gigi_accept
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
GIGI_SOCKET gigi_accept (GIGIONE gg, GIGI_ID * from,
                         GIGI_ID service_id, int timeout);

/*
 * function gigi_open_service
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
GIGI_SERVICE gigi_open_service (GIGIONE gg, GIGI_ID service_id, int backlog);

/*
 * function gigi_close_service
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
int gigi_close_service (GIGI_SERVICE service);

/*
 * function gigi_send_object
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
int gigi_send_object (GIGI_SOCKET fd, int type, const void * buff, int size);

/*
 * function gigi_recv_object
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
int gigi_recv_object (GIGI_SOCKET fd, int type, void * buff, int * size);

/*
 * function  gigi_type_register 
 *           
 * return --- 
 *  type_list(in) : 
 *  reg           : 
 */
int gigi_type_register (GIGI_TYPE_LIST type_list, int reg);

/*
 * function gigi_type
 *          return type define object of custom type
 * return --- type define object
 * type   --- type id
 */
GIGI_TYPE_DEF gigi_type (int type);


/*
 *   APIs list -- Part 4
 *
 *   gigi_register_mpi_func
 *   gigi_mpi_func_def
 *   gmpi_create
 *   gmpi_run
 *   gmpi_accept
 *   gmpi_send
 *   gmpi_recv
 *   gmpi_rank
 *   gmpi_size
 *   gmpi_remote_call
 *   gmpi_call
 *   gmpi_service
 *   gmpi_context
 *   gmpi_bcast
 *   gmpi_reduce
 *   gmpi_reduce
 *   gmpi_get_nodes_of_group
 *   gmpi_get_node_id
 *
 */

/*
 * function gigi_register_mpi_func
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
int gigi_register_mpi_func (GIGIONE gg, GMPI_FUNC_DEF funcs, int reg);

/*
 * function gigi_mpi_func_def
 *          
 * return   --- 
 * gg       --- the handle of GIGIONE context
 * name(in) --- name of mpi func
 */
GMPI_FUNC_DEF gigi_mpi_func_def (GIGIONE gg, GIGI_LPCSTR name);

/*
 * function gmpi_create
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
GIGI_MPI gmpi_create (GIGIONE gg, GMPI_FUNC_DEF func,
                      GIGI_ID * nodes, int count);

/*
 * function gmpi_run
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
int gmpi_run (GIGI_MPI mpi, void * param, GIGI_ID service_id, int timeout);

/*
 * function gigi_accept_task
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
GIGI_MPI gmpi_accept (GIGIONE gg, GIGI_ID service_id, int timeout);

/*
 * function gmpi_remote_call
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
GIGI_SOCKET gmpi_remote_call (const char* func_name, unsigned ip,
                               int port, GIGI_ID service_id);

/*
 * function gmpi_call
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
#define gmpi_call(gg, func, nodes, count, param, service_id, timeout)\
  gmpi_run (gmpi_create (gg, func, nodes, count), param, service_id, timeout)

/*
 * function gmpi_service
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
#define gmpi_service(gg, param, service_id, timeout)\
  gmpi_run (gmpi_accept (gg, service_id, timeout), param, service_id, timeout)

/*
 * function gmpi_rank
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
int gmpi_rank (GIGI_MPI mpi);

/*
 * function gmpi_size
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
int gmpi_size (GIGI_MPI mpi);

/*
 * function gmpi_context
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
GIGIONE gmpi_context (GIGI_MPI mpi);

/*
 * function gmpi_send
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
int gmpi_send (GIGI_MPI mpi, int type, void * buff, int size, int id);

/*
 * function gmpi_recv
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
int gmpi_recv (GIGI_MPI mpi, int type, void * buff, int * size, int id);

/*
 * function gmpi_get_nodes_of_group
 *          
 * return --- 
 * gg     --- the handle of GIGIONE context
 */
int gmpi_get_nodes_of_group (GIGI_MPI mpi, GIGI_ID * nodes, int count);

/*
 * function gmpi_get_node_id
 *          
 * return --- 
 * mpi    --- mpi object
 */
GIGI_ID gmpi_get_node_id (GIGI_MPI mpi, int id);

/*
 * function gmpi_bcast
 *          
 * return --- 
 * mpi    --- mpi object
 */
int gmpi_bcast (GIGI_MPI mpi, int type, void * buff,
                 int * size,int root);

/*
 * function gmpi_reduce
 *          
 * return --- 
 * mpi    --- mpi object
 */
int gmpi_reduce (GIGI_MPI mpi, GIGI_REDUCE_OP op, int type,
                  void * buff, int * count, int root);

/*
 * function gmpi_sync
 *          
 * return --- 
 * mpi    --- mpi object
 * op     --- 
 * type   ---
 * buff   ---
 * count  ---
 */
int gmpi_sync (GIGI_MPI mpi, GIGI_REDUCE_OP op, int type,
                void * buff, int * count);


#ifdef __cplusplus
}
#endif

#endif  /* end of __GIGIONE_H__ */


